/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef INCLUDE_ARCHV8R_REGISTER_H
#define INCLUDE_ARCHV8R_REGISTER_H

#if !defined(ASSEMBLY)

#include <Compiler.h>
#include "barriers.h"
#define uint32_t uint32
#define uint64_t uint64
#define uint16_t uint16
#define uint8_t uint8

static inline uint32_t read_cpsr(void)
{
    uint32_t cpsr;
    ASM volatile("mrs   %0, cpsr" : "=r"(cpsr));
    return cpsr;
}

#define ARM_CP_REG_FUNCS(cp, reg, op1, c1, c2, op2)                                                                    \
    static inline uint32_t arm_read_##reg(void)                                                                        \
    {                                                                                                                  \
        uint32_t val;                                                                                                  \
        ASM volatile("mrc " #cp ", " #op1 ", %0, " #c1 "," #c2 "," #op2 : "=r"(val));                                \
        return val;                                                                                                    \
    }                                                                                                                  \
                                                                                                                       \
    static inline void arm_write_##reg(uint32_t val)                                                                   \
    {                                                                                                                  \
        ASM volatile("mcr " #cp ", " #op1 ", %0, " #c1 "," #c2 "," #op2 ::"r"(val));                                 \
        ISB;                                                                                                           \
    }

#define ARM_CP_REG64_FUNCS(cp, reg, op1, c1)                                                                           \
    static inline uint64_t arm_read64_##reg(void)                                                                      \
    {                                                                                                                  \
        uint64_t val;                                                                                                  \
        ASM volatile("mrrc " #cp ", " #op1 ", %Q0, %R0, " #c1 : "=r"(val)::"memory");                                \
        return val;                                                                                                    \
    }                                                                                                                  \
                                                                                                                       \
    static inline void arm_write64_##reg(uint64_t val)                                                                 \
    {                                                                                                                  \
        ASM volatile("mcrr " #cp ", " #op1 ", %Q0, %R0, " #c1 ::"r"(val) : "memory");                                \
        ISB;                                                                                                           \
    }

#define ARM_CP15_REG_FUNCS(reg, op1, c1, c2, op2) ARM_CP_REG_FUNCS(p15, reg, op1, c1, c2, op2)
#define ARM_CP15_REG64_FUNCS(reg, op1, c1)        ARM_CP_REG64_FUNCS(p15, reg, op1, c1)

#define ARM_CP14_REG_FUNCS(reg, op1, c1, c2, op2) ARM_CP_REG_FUNCS(p14, reg, op1, c1, c2, op2)

#define ARM_CP10_REG_FUNCS(reg, op1, c1, c2, op2) ARM_CP_REG_FUNCS(p10, reg, op1, c1, c2, op2)

// // PRQA S 0605 ++
ARM_CP15_REG_FUNCS(sctlr, 0, c1, c0, 0);
ARM_CP15_REG_FUNCS(actlr, 0, c1, c0, 1);
ARM_CP15_REG_FUNCS(cpacr, 0, c1, c0, 2);

// ARM_CP15_REG_FUNCS(ttbr, 0, c2, c0, 0);
// ARM_CP15_REG_FUNCS(ttbr0, 0, c2, c0, 0);
// ARM_CP15_REG_FUNCS(ttbr1, 0, c2, c0, 1);
// ARM_CP15_REG_FUNCS(ttbcr, 0, c2, c0, 2);
ARM_CP15_REG_FUNCS(vsctlr, 4, c2, c0, 0);
// ARM_CP15_REG_FUNCS(dacr, 0, c3, c0, 0);
ARM_CP15_REG_FUNCS(dfsr, 0, c5, c0, 0);
ARM_CP15_REG_FUNCS(ifsr, 0, c5, c0, 1);
ARM_CP15_REG_FUNCS(dfar, 0, c6, c0, 0);
// ARM_CP15_REG_FUNCS(wfar, 0, c6, c0, 1);
ARM_CP15_REG_FUNCS(ifar, 0, c6, c0, 2);

ARM_CP15_REG_FUNCS(fcseidr, 0, c13, c0, 0);
ARM_CP15_REG_FUNCS(contextidr, 0, c13, c0, 1);
ARM_CP15_REG_FUNCS(tpidrurw, 0, c13, c0, 2);
ARM_CP15_REG_FUNCS(tpidruro, 0, c13, c0, 3);
ARM_CP15_REG_FUNCS(tpidrprw, 0, c13, c0, 4);

ARM_CP15_REG_FUNCS(midr, 0, c0, c0, 0);
ARM_CP15_REG_FUNCS(mpidr, 0, c0, c0, 5);
ARM_CP15_REG_FUNCS(vbar, 0, c12, c0, 0);
ARM_CP15_REG_FUNCS(cbar, 1, c15, c3, 0);

ARM_CP15_REG_FUNCS(ats1cpr, 0, c7, c8, 0);
ARM_CP15_REG_FUNCS(ats1cpw, 0, c7, c8, 1);
ARM_CP15_REG_FUNCS(ats1cur, 0, c7, c8, 2);
ARM_CP15_REG_FUNCS(ats1cuw, 0, c7, c8, 3);
ARM_CP15_REG_FUNCS(ats12nsopr, 0, c7, c8, 4);
ARM_CP15_REG_FUNCS(ats12nsopw, 0, c7, c8, 5);
ARM_CP15_REG_FUNCS(ats12nsour, 0, c7, c8, 6);
ARM_CP15_REG_FUNCS(ats12nsouw, 0, c7, c8, 7);
ARM_CP15_REG_FUNCS(par, 0, c7, c4, 0);

/* Branch predictor invalidate */
ARM_CP15_REG_FUNCS(bpiall, 0, c7, c5, 6);
ARM_CP15_REG_FUNCS(bpimva, 0, c7, c5, 7);
ARM_CP15_REG_FUNCS(bpiallis, 0, c7, c1, 6);

// ARM_CP15_REG_FUNCS(l2ctlr, 1, c9, c0, 2);
// ARM_CP15_REG_FUNCS(l2ectlr, 1, c9, c0, 3);

/* mpu registers (using unified memory regions) */
ARM_CP15_REG_FUNCS(mpuir, 0, c0, c0, 4);
ARM_CP15_REG_FUNCS(prbar, 0, c6, c3, 0);
ARM_CP15_REG_FUNCS(prlar, 0, c6, c3, 1);
ARM_CP15_REG_FUNCS(prselr, 0, c6, c2, 1);
ARM_CP15_REG_FUNCS(mair0, 0, c10, c2, 0);
ARM_CP15_REG_FUNCS(mair1, 0, c10, c2, 1);

/* performance monitor registers */
ARM_CP15_REG_FUNCS(pmcr, 0, c9, c12, 0);
ARM_CP15_REG_FUNCS(pmcntenset, 0, c9, c12, 1);
ARM_CP15_REG_FUNCS(pmcntenclr, 0, c9, c12, 2);
ARM_CP15_REG_FUNCS(pmovsr, 0, c9, c12, 3);
ARM_CP15_REG_FUNCS(pmswinc, 0, c9, c12, 4);
ARM_CP15_REG_FUNCS(pmselr, 0, c9, c12, 5);
ARM_CP15_REG_FUNCS(pmccntr, 0, c9, c13, 0);
ARM_CP15_REG_FUNCS(pmxevtyper, 0, c9, c13, 1);
ARM_CP15_REG_FUNCS(pmxevcntr, 0, c9, c13, 2);

/* TCM registers */
ARM_CP15_REG_FUNCS(tcmtr, 0, c0, c0, 2);
ARM_CP15_REG_FUNCS(atcmrgn, 0, c9, c1, 0);
ARM_CP15_REG_FUNCS(btcmrgn, 0, c9, c1, 1);
ARM_CP15_REG_FUNCS(ctcmrgn, 0, c9, c1, 2);

/* debug registers */
ARM_CP14_REG_FUNCS(dbddidr, 0, c0, c0, 0);
ARM_CP14_REG_FUNCS(dbgdrar, 0, c1, c0, 0);
ARM_CP14_REG_FUNCS(dbgdsar, 0, c2, c0, 0);
ARM_CP14_REG_FUNCS(dbgdscr, 0, c0, c1, 0);
ARM_CP14_REG_FUNCS(dbgdtrtxint, 0, c0, c5, 0);
ARM_CP14_REG_FUNCS(dbgdtrrxint, 0, c0, c5, 0);
ARM_CP14_REG_FUNCS(dbgwfar, 0, c0, c6, 0);
ARM_CP14_REG_FUNCS(dbgvcr, 0, c0, c7, 0);
// ARM_CP14_REG_FUNCS(dbgecr, 0, c0, c9, 0);
// ARM_CP14_REG_FUNCS(dbgdsccr, 0, c0, c10, 0);
// ARM_CP14_REG_FUNCS(dbgdsmcr, 0, c0, c11, 0);
ARM_CP14_REG_FUNCS(dbgdtrrxext, 0, c0, c0, 2);
ARM_CP14_REG_FUNCS(dbgdscrext, 0, c0, c2, 2);
ARM_CP14_REG_FUNCS(dbgdtrtxext, 0, c0, c3, 2);
// ARM_CP14_REG_FUNCS(dbgdrcr, 0, c0, c4, 2);
ARM_CP14_REG_FUNCS(dbgvr0, 0, c0, c0, 4);
ARM_CP14_REG_FUNCS(dbgvr1, 0, c0, c1, 4);
ARM_CP14_REG_FUNCS(dbgvr2, 0, c0, c2, 4);
ARM_CP14_REG_FUNCS(dbgbcr0, 0, c0, c0, 5);
ARM_CP14_REG_FUNCS(dbgbcr1, 0, c0, c1, 5);
ARM_CP14_REG_FUNCS(dbgbcr2, 0, c0, c2, 5);
ARM_CP14_REG_FUNCS(dbgwvr0, 0, c0, c0, 6);
ARM_CP14_REG_FUNCS(dbgwvr1, 0, c0, c1, 6);
ARM_CP14_REG_FUNCS(dbgwvr2, 0, c0, c2, 6);
ARM_CP14_REG_FUNCS(dbgwcr0, 0, c0, c0, 7);
ARM_CP14_REG_FUNCS(dbgwcr1, 0, c0, c1, 7);
ARM_CP14_REG_FUNCS(dbgwcr2, 0, c0, c2, 7);
ARM_CP14_REG_FUNCS(dbgoslar, 0, c1, c0, 4);
ARM_CP14_REG_FUNCS(dbgoslsr, 0, c1, c1, 4);
// ARM_CP14_REG_FUNCS(dbgossrr, 0, c1, c2, 4);
ARM_CP14_REG_FUNCS(dbgprcr, 0, c1, c4, 4);
// ARM_CP14_REG_FUNCS(dbgprsr, 0, c1, c5, 4);
ARM_CP14_REG_FUNCS(dbgclaimset, 0, c7, c8, 6);
ARM_CP14_REG_FUNCS(dbgclaimclr, 0, c7, c9, 6);
ARM_CP14_REG_FUNCS(dbgauthstatus, 0, c7, c14, 6);
ARM_CP14_REG_FUNCS(dbgdevid, 0, c7, c2, 7);

/* Generic timer registers */
ARM_CP15_REG_FUNCS(cntfrq, 0, c14, c0, 0);
ARM_CP15_REG64_FUNCS(cntpct, 0, c14);
ARM_CP15_REG_FUNCS(cntpctl, 0, c14, c2, 1);
ARM_CP15_REG_FUNCS(cntptval, 0, c14, c2, 0);
ARM_CP15_REG64_FUNCS(cntpcval, 2, c14);

/* GIC registers */
ARM_CP15_REG_FUNCS(iccpmr, 0, c4, c6, 0);
ARM_CP15_REG_FUNCS(iccrpr, 0, c12, c11, 3);
ARM_CP15_REG_FUNCS(icciar0, 0, c12, c8, 0);
ARM_CP15_REG_FUNCS(icciar1, 0, c12, c12, 0);
ARM_CP15_REG_FUNCS(icceoir0, 0, c12, c8, 1);
ARM_CP15_REG_FUNCS(icceoir1, 0, c12, c12, 1);
ARM_CP15_REG_FUNCS(iccsre, 0, c12, c12, 5);
ARM_CP15_REG_FUNCS(icchsre, 4, c12, c9, 5);
ARM_CP15_REG_FUNCS(iccbpr0, 0, c12, c8, 3);
ARM_CP15_REG_FUNCS(iccbpr1, 0, c12, c12, 3);
ARM_CP15_REG_FUNCS(iccigrpen0, 0, c12, c12, 6);
ARM_CP15_REG_FUNCS(iccigrpen1, 0, c12, c12, 7);
ARM_CP15_REG64_FUNCS(iccsgi1r, 0, c12);
ARM_CP15_REG_FUNCS(memportctrl, 1, c9, c1, 2);


/* fpu registers */
static inline uint32_t arm_read_fpexc(void)
{
    uint32_t val;
    ASM volatile("fmrx r0, fpexc" : "=r"(val));
    return val;
}

static inline void arm_write_fpexc(uint32_t val)
{
    ASM volatile("fmxr fpexc, %0" ::"r"(val));
    ISB;
}
// PRQA S 0605 --
#endif /* ASSEMBLY */

#endif /* INCLUDE_ARCHV8R_REGISTER_H */
